home *** CD-ROM | disk | FTP | other *** search
Wrap
/* Miranda Installer - Installs nightlies and Miranda addons. Copyright (C) 2002-2003 Goblineye Entertainment Authors: Saar (Tornado) and Kai (kai_b) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "Worker.h" #pragma hdrstop // handle the file pattern, we might need to create subdirectories for this file // we do not write the file though, we just create directories and such // szFilename is filename reported from Zip entry, szDestDir is the destination directory __forceinline void Handle_File_Pattern(const char *szFilename,const char *szDestDir) { const char *lpNS = szFilename; char szMD[MAX_PATH + 1]; char szComp[MAX_PATH + 1]; // component of directory tree lpNS = strchr(lpNS,'\\'); while (lpNS != NULL) // find the next one { lstrcpy(szMD,szDestDir); lstrcat(szMD,"\\"); lstrcpyn(szComp,szFilename,lpNS - szFilename + 1); // szComp[lpNS - szFilename] = '\0'; lstrcat(szMD,szComp); // add it CreateDirectory(szMD,NULL); // create it lpNS = strchr(lpNS+1,'\\'); } } __forceinline void Validate_Directory(const char *szDirectory) // make sure directory exists { const char *lpSlash = strchr(szDirectory,'\\'); char szTemp[MAX_PATH + 1]; while (lpSlash != NULL) { // btw: last char can't be a slash (we prevent it) lstrcpyn(szTemp,szDirectory,lpSlash - szDirectory + 1); // don't copy the slash CreateDirectory(szTemp,NULL); lpSlash = strchr(lpSlash+1,'\\'); } // now create final directory CreateDirectory(szDirectory,NULL); } // does the actual dirty dirty work of installing the current file in the .zip (The function takes care of opening it and closing it later) // this function needs to handle events such as: 1) the dest file already exists, and it is read-only. 2) sub-directories (That's actually handled by another function...) // *NO* errors are handled here! // NADA // the caller will be notified of the failure, and will show some warning on its own static bool Worker_InstallFile(unzFile hFile,HWND hwndDlg,int iItemID,const char *lpDestDir) { char szDestFile[MAX_PATH + 1]; char szFilename[MAX_PATH + 1]; unzGetCurrentFileInfo(hFile,NULL,szFilename,MAX_PATH+1,NULL,0,NULL,0); Validate_Directory(lpDestDir); // make sure directory exists // reverse slashes Switch_Slashes(szFilename,false); if (*(szFilename + lstrlen(szFilename) - 1) != '\\') // meaning it's not a directory, we ignore directories { Handle_File_Pattern(szFilename,lpDestDir); lstrcpy(szDestFile,lpDestDir); // destination directory lstrcat(szDestFile,"\\"); lstrcat(szDestFile,szFilename); /* // this isn't needed // read-only files can't be overwritten // before we do anything, let's figure out if we're supposed to overwrite this file if (g_WorkOptions.dwFlags & 1) // ask if to overwrite { DWORD dwAtts = GetFileAttributes(szDestFile); if ((dwAtts != INVALID_FILE_ATTRIBUTES) && (dwAtts & FILE_ATTRIBUTE_READONLY)) // alert the user { char szMsg[512]; wsprintf(szMsg,"The read-only file %s already exists, would you like to overwrite it?",szDestFile); if (MessageBox(hwndDlg,szMsg,"buya",MB_ICONQUESTION | MB_YESNO) == IDNO) { return(true); } } } */ // notify the master thingy we're about to start extraction // no need to strip the relative path from the filename // it's kinda nice :) SendMessage(hwndDlg,MIRINST_INFOMSG_EXTRACTING,iItemID,(LPARAM)szFilename); if (unzOpenCurrentFile(hFile) != UNZ_OK) { return(false); } FILE *hDecompFile = fopen(szDestFile,"wb"); if (hDecompFile != NULL) { char cData[2048]; while (1) { int iRead = unzReadCurrentFile(hFile,cData,sizeof(cData)); if (iRead > 0) { if (fwrite(cData,1,iRead,hDecompFile) != (unsigned int)iRead) { // problems, bahh unzCloseCurrentFile(hFile); fclose(hDecompFile); DeleteFile(szDestFile); // get rid of it return(false); } } else { break; } } fclose(hDecompFile); } if (unzCloseCurrentFile(hFile) == UNZ_CRCERROR) // problem { return(false); } } return(true); // not an error, means we're not going to install a directory! } // used by routine void XMLHandler_InspectAutorun(byte bMsg,char *lpszData,unsigned long ulLen,LPARAM lParam) { static byte s_bDepth; // depth of script. not really used the way you think it's used :) static char s_szElement[32]; // long enough switch(bMsg) { case XMLPARSER_NOTIFY_STARTELEMENT: { if (s_bDepth == 2) // inside autorun { // remember the element type if (ulLen < 32) // just the right size { strncpy(s_szElement,lpszData,ulLen); s_szElement[ulLen] = '\0'; AUTORUN_INFO *pARInfo = (AUTORUN_INFO*)lParam; // if we *haven't* finished finding an autorun section yet (we limit to one) if ((!(pARInfo->bState & 1)) && (lstrcmpi(s_szElement,"document") == 0)) // document { pARInfo->bState |= 2; // document } } else { s_szElement[0] = '\0'; // no element, can't be (our tags are shorter) } } else if (_strnicmp(lpszData,"installscript",ulLen) == 0) // going into script { if (s_bDepth == 0) { s_bDepth++; } } else if (_strnicmp(lpszData,"autorun",ulLen) == 0) // autorun section { if (s_bDepth == 1) { s_bDepth++; } } } break; case XMLPARSER_NOTIFY_ENDELEMENT: { if (_strnicmp(lpszData,"installscript",ulLen) == 0) // done with installscript { if (s_bDepth == 1) { s_bDepth--; } } else if (_strnicmp(lpszData,"autorun",ulLen) == 0) // done with autorun { if (s_bDepth == 2) { s_bDepth--; ((AUTORUN_INFO*)lParam)->bState |= 1; // finished an autorun section } } } break; case XMLPARSER_NOTIFY_DATA: { if ((s_bDepth == 2) && (ulLen > 0)) // do we have info in there? { AUTORUN_INFO *pARInfo = (AUTORUN_INFO*)lParam; // make sure we only have one file!! if ((pARInfo->lpFilename == NULL) && (!(pARInfo->bState & 1)) && (lstrcmpi(s_szElement,"file") == 0)) { pARInfo->lpFilename = new char[ulLen + 1]; lstrcpyn(pARInfo->lpFilename,lpszData,ulLen+1); Switch_Slashes(pARInfo->lpFilename,true); // switch slashes (to slashes) } } } break; } } // used by routine void XMLHandler_GetFilesPackages(byte bMsg,char *lpszData,unsigned long ulLen,LPARAM lParam) { static byte s_bDepth; // depth of script. not really used the way you think it's used :) static char s_szElement[32]; // long enough static bool s_fOptional; // files are first added to the WORKER_FILELIST list // if they should be added to final, then they are added to master list static GENERAL_FILELIST *s_pFileList; switch(bMsg) { case XMLPARSER_NOTIFY_STARTELEMENT: { if (s_bDepth == 2) // inside packageinfo { // remember the element type if (ulLen < 32) // just the right size { strncpy(s_szElement,lpszData,ulLen); s_szElement[ulLen] = '\0'; if (lstrcmpi(s_szElement,"optional") == 0) // optional { s_fOptional = true; } } else { s_szElement[0] = '\0'; // no element, can't be (our tags are shorter) } } else if (_strnicmp(lpszData,"installscript",ulLen) == 0) // going into script { if (s_bDepth == 0) { s_bDepth++; } } else if (_strnicmp(lpszData,"packageinfo",ulLen) == 0) // packageinfo realm { s_fOptional = false; s_pFileList = NULL; if (s_bDepth == 1) { s_bDepth++; } } } break; case XMLPARSER_NOTIFY_ENDELEMENT: { if (_strnicmp(lpszData,"installscript",ulLen) == 0) // done with installscript { if (s_bDepth == 1) { s_bDepth--; } } else if (_strnicmp(lpszData,"packageinfo",ulLen) == 0) // done with packageinfo { if (s_bDepth == 2) { s_bDepth--; // OK, now... // we add the list from s_pFileList // to the list given by the caller // the temp list is then deleted - correction - it's not deleted, just added to the master list // no dupe checks are made, that's up to the initial probe XMLINSTALLER_EXTRAINFO *pExtraInfo = (XMLINSTALLER_EXTRAINFO*)lParam; if (s_pFileList == NULL) // ? no files! { Cleanup_FileList(&s_pFileList); } else if ((pExtraInfo->bSolution == 2) && (s_fOptional)) // mismatch, this is optional, we only install main { // cleanup Cleanup_FileList(&s_pFileList); } else // ok we give the caller the list we got. we just add it to the end of the current list. { // add it in if (pExtraInfo->pFileList == NULL) // empty { pExtraInfo->pFileList = s_pFileList; } else { GENERAL_FILELIST *pCur = pExtraInfo->pFileList; while (pCur->next != NULL) { pCur = pCur->next; } // pCur->next is insertion point pCur->next = s_pFileList; } s_pFileList = NULL; // clear local pointer } } } } break; case XMLPARSER_NOTIFY_DATA: { if ((s_bDepth == 2) && (ulLen > 0)) // do we have info in there? { if (lstrcmpi(s_szElement,"file") == 0) // author, let's get it { GENERAL_FILELIST *node = new GENERAL_FILELIST; node->lpFilename = new char[ulLen + 1]; lstrcpyn(node->lpFilename,lpszData,ulLen+1); Switch_Slashes(node->lpFilename,true); // switch slashes (to slashes) // add to list node->next = s_pFileList; s_pFileList = node; } } } break; } } // used by dialog void XMLHandler_ProbePackages(byte bMsg,char *lpszData,unsigned long ulLen,LPARAM lParam) { static byte s_bDepth; // depth of script. not really used the way you think it's used :) static char s_szElement[32]; // long enough static PS_PACKAGEINFO s_PackageInfo; // package info - zeroed every new package static PS_FILELIST *s_pFileList; // per-package switch(bMsg) { case XMLPARSER_NOTIFY_STARTELEMENT: { if (s_bDepth == 2) // inside packageinfo { // remember the element type if (ulLen < 32) // just the right size { strncpy(s_szElement,lpszData,ulLen); s_szElement[ulLen] = '\0'; if (lstrcmpi(s_szElement,"optional") == 0) // optional { s_PackageInfo.fOptional = true; } } else { s_szElement[0] = '\0'; // no element, can't be (our tags are shorter) } } else if (_strnicmp(lpszData,"installscript",ulLen) == 0) // going into script { if (s_bDepth == 0) { s_bDepth++; } } else if (_strnicmp(lpszData,"packageinfo",ulLen) == 0) // packageinfo realm { ZeroMemory(&s_PackageInfo,sizeof(PS_PACKAGEINFO)); s_pFileList = NULL; if (s_bDepth == 1) { s_bDepth++; } } } break; case XMLPARSER_NOTIFY_ENDELEMENT: { if (_strnicmp(lpszData,"installscript",ulLen) == 0) // done with installscript { if (s_bDepth == 1) { s_bDepth--; } } else if (_strnicmp(lpszData,"packageinfo",ulLen) == 0) // done with packageinfo { if (s_bDepth == 2) { s_bDepth--; XMLPROBE_SCRIPTINFO *pScriptInfo = (XMLPROBE_SCRIPTINFO*)lParam; // if (s_pFileList == NULL) // ? no files! // { // MessageBox(NULL,"Argg!!","bla",0); // } // else if (s_pFileList != NULL) { // add it in if (s_PackageInfo.lpTitle == NULL) // argg, bad! { s_PackageInfo.lpTitle = new char[lstrlen(DEFAULT_PACKAGENAME) + 1]; lstrcpy(s_PackageInfo.lpTitle,DEFAULT_PACKAGENAME); } // ok let's see where is this supposed to go // go through current packages WORD wInsertPos = (WORD)SendMessage(pScriptInfo->hwndCtrl,PSM_GETPACKAGECOUNT,0,0); for (WORD index=0,iCount = wInsertPos;index < iCount;index++) { PS_PACKAGEINFO *pPackageInfo = (PS_PACKAGEINFO*)SendMessage(pScriptInfo->hwndCtrl,PSM_GETPACKAGEINFO,index,0); if (pPackageInfo->fOptional == s_PackageInfo.fOptional) // same. comparison is by name { if (lstrcmpi(pPackageInfo->lpTitle,s_PackageInfo.lpTitle) >= 0) // insert here { wInsertPos = index; break; } } else if (pPackageInfo->fOptional) // remote package is optional, insert here { wInsertPos = index; break; } } WORD wPackageID = (WORD)SendMessage(pScriptInfo->hwndCtrl,PSM_ADDPACKAGE,wInsertPos,(LPARAM)&s_PackageInfo); PS_FILELIST *pCur = s_pFileList; while (pCur != NULL) { SendMessage(pScriptInfo->hwndCtrl,PSM_ADDFILE,wPackageID,(LPARAM)&(pCur->fileInfo)); pCur = pCur->next; } } // then clear it... PS_FILELIST *pCur = s_pFileList; while (pCur != NULL) { PS_FILELIST *pNext = pCur->next; delete pCur; pCur = pNext; } // NOTE we DO NOT delete the allocated title nor filename! that's up to the package selector } } } break; case XMLPARSER_NOTIFY_DATA: { if ((s_bDepth == 2) && (ulLen > 0)) // do we have info in there? { if (lstrcmpi(s_szElement,"title") == 0) // name of package { s_PackageInfo.lpTitle = new char[ulLen + 1]; lstrcpyn(s_PackageInfo.lpTitle,lpszData,ulLen+1); } else if (lstrcmpi(s_szElement,"file") == 0) // author, let's get it { XMLPROBE_SCRIPTINFO *pScriptInfo = (XMLPROBE_SCRIPTINFO*)lParam; PS_FILELIST *node = new PS_FILELIST; node->fileInfo.lpFilename = new char[ulLen + 1]; lstrcpyn(node->fileInfo.lpFilename,lpszData,ulLen+1); node->fileInfo.dwFileSize = 0; // init // now we *try* to find this file we got, and find its size // no need to remember our current position // before we do anything, let's switch slashes // remember this is from the script, this will turn any backslashes to slashes Switch_Slashes(node->fileInfo.lpFilename,true); if (unzLocateFile(pScriptInfo->hFile,node->fileInfo.lpFilename,2) == UNZ_OK) // try to find the file { // got it unz_file_info fileInfo; unzGetCurrentFileInfo(pScriptInfo->hFile,&fileInfo,NULL,0,NULL,0,NULL,0); // we need its size node->fileInfo.dwFileSize = fileInfo.uncompressed_size; } // now switch back to backslashes Switch_Slashes(node->fileInfo.lpFilename,false); // add to list (always at beginning) node->next = s_pFileList; s_pFileList = node; } } } break; } } INT_PTR CALLBACK PackagesDlgProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam) { switch(uMsg) { case WM_INITDIALOG: { PACKAGEDLG_EXTRAINFO *pExtraInfo = (PACKAGEDLG_EXTRAINFO*)lParam; SetWindowLongPtr(hwndDlg,GWLP_USERDATA,(LONG_PTR)pExtraInfo); XMLPROBE_SCRIPTINFO *pScriptInfo = new XMLPROBE_SCRIPTINFO; pScriptInfo->hFile = pExtraInfo->hFile; pScriptInfo->hwndCtrl = GetDlgItem(hwndDlg,IDC_PACKAGEDLG_SELECTOR); // ok now process script XMLParser_FeedDocument(XMLHandler_ProbePackages,pExtraInfo->lpScript,(LPARAM)pScriptInfo); delete pScriptInfo; // ok now finish off the rest of the dialog char szTitle[128], szFormatted[256]; // big enough GetDlgItemText(hwndDlg,IDC_PACKAGEDLG_TITLE,szTitle,512); wsprintf(szFormatted,Translate(szTitle),pExtraInfo->szFilename); // format filename into string SetDlgItemText(hwndDlg,IDC_PACKAGEDLG_TITLE,szFormatted); // select all as default SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_INSTALLALL,BM_CLICK,0,0); // simulate a click (selection) // now go through all packages and set dialog info // this info *could* be received by caller, but this is a better approach, in a sense WORD wMainFiles = 0, wAllFiles = 0; DWORD dwMainSize = 0, dwAllSize = 0; for (WORD index=0, wCount = (WORD)SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_SELECTOR,PSM_GETPACKAGECOUNT,0,0);index < wCount;index++) { PS_PACKAGEINFO *pPackageInfo = (PS_PACKAGEINFO*)SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_SELECTOR,PSM_GETPACKAGEINFO,index,0); WORD wPackageFiles = (WORD)SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_SELECTOR,PSM_GETFILECOUNT,index,0); DWORD dwPackageSize = 0; // calc package size for (WORD index2=0;index2 < wPackageFiles;index2++) { PS_FILEINFO *pFileInfo = (PS_FILEINFO*)SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_SELECTOR,PSM_GETFILEINFO,index2,(LPARAM)pPackageInfo); dwPackageSize += pFileInfo->dwFileSize; } if (!pPackageInfo->fOptional) { wMainFiles += wPackageFiles; dwMainSize += dwPackageSize; } wAllFiles += wPackageFiles; dwAllSize += dwPackageSize; } char szTemp[128], szFileSize[32]; Format_DisplaySize(szFileSize,dwAllSize); wsprintf(szTemp,Translate("%d file/s (%s)"),wAllFiles,szFileSize); SetDlgItemText(hwndDlg,IDC_PACKAGEDLG_STATIC_ALLINFO,szTemp); Format_DisplaySize(szFileSize,dwMainSize); wsprintf(szTemp,Translate("%d file/s (%s)"),wMainFiles,szFileSize); SetDlgItemText(hwndDlg,IDC_PACKAGEDLG_STATIC_MAININFO,szTemp); if (wMainFiles == wAllFiles) // no optional packages { // having both enabled, even though we don't have optional packages will give problems // this is just a quick workaround, but it's best this way EnableWindow(GetDlgItem(hwndDlg,IDC_PACKAGEDLG_INSTALLMAIN),false); // avoid mixups EnableWindow(GetDlgItem(hwndDlg,IDC_PACKAGEDLG_STATIC_MAININFO),false); // avoid mixups } // clean up is done on destruction of dialog LP_TranslateDialog(hwndDlg); return(true); } break; case WM_COMMAND: { if (HIWORD(wParam) == BN_CLICKED) // If we clicked { switch (LOWORD(wParam)) { case IDOK: { // start installing PACKAGEDLG_EXTRAINFO *pExtraInfo = (PACKAGEDLG_EXTRAINFO*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA); unzFile hFile = pExtraInfo->hFile; // go through selected packages and copy filenames to be installed for (WORD index=0, wCount = (WORD)SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_SELECTOR,PSM_GETPACKAGECOUNT,0,0);index < wCount;index++) { PS_PACKAGEINFO *pPackageInfo = (PS_PACKAGEINFO*)SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_SELECTOR,PSM_GETPACKAGEINFO,index,0); if (pPackageInfo->fSelected) // selected { for (WORD index2 = 0, wFileCount = (WORD)SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_SELECTOR,PSM_GETFILECOUNT,index,0);index2 < wFileCount;index2++) { PS_FILEINFO *pFileInfo = (PS_FILEINFO*)SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_SELECTOR,PSM_GETFILEINFO,index2,(LPARAM)pPackageInfo); GENERAL_FILELIST *node = new GENERAL_FILELIST; node->lpFilename = new char[lstrlen(pFileInfo->lpFilename) + 1]; lstrcpy(node->lpFilename,pFileInfo->lpFilename); // add it node->next = pExtraInfo->pFileList; pExtraInfo->pFileList = node; } } } // return solution type EndDialog(hwndDlg,((IsWindowEnabled(GetDlgItem(hwndDlg,IDC_PACKAGEDLG_DOTHESAME))) && (IsDlgButtonChecked(hwndDlg,IDC_PACKAGEDLG_DOTHESAME) == BST_CHECKED)) ? (((IsDlgButtonChecked(hwndDlg,IDC_PACKAGEDLG_INSTALLALL) == BST_CHECKED) ? (1) : (((IsDlgButtonChecked(hwndDlg,IDC_PACKAGEDLG_INSTALLMAIN) == BST_CHECKED) ? (2) : (0))))) : (0)); return(true); } break; case IDCANCEL: { // return (we cancel!) EndDialog(hwndDlg,0xFF); return(true); } break; case IDC_PACKAGEDLG_INSTALLALL: case IDC_PACKAGEDLG_INSTALLMAIN: { // select appropriate packages from control for (WORD index=0, wCount = (WORD)SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_SELECTOR,PSM_GETPACKAGECOUNT,0,0);index < wCount;index++) { PS_PACKAGEINFO *pPackageInfo = (PS_PACKAGEINFO*)SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_SELECTOR,PSM_GETPACKAGEINFO,index,0); bool fSelect = true; if ((pPackageInfo->fOptional) && (LOWORD(wParam) != IDC_PACKAGEDLG_INSTALLALL)) // we don't install all { fSelect = false; } SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_SELECTOR,PSM_SELECTPACKAGE,index,fSelect); } SendMessage(hwndDlg,PSN_PACKAGESELCHANGE,0,0); // handle change (not done for us) return(true); } break; } } } break; case PSN_PACKAGESELCHANGE: // change in selection { // check selection state bool fMainOnly = true; WORD wSelectCount = 0, wSelectFiles = 0, wTotalFiles = 0; DWORD dwSelectSize = 0, dwTotalSize = 0; for (WORD index=0, wCount = (WORD)SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_SELECTOR,PSM_GETPACKAGECOUNT,0,0);index < wCount;index++) { PS_PACKAGEINFO *pPackageInfo = (PS_PACKAGEINFO*)SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_SELECTOR,PSM_GETPACKAGEINFO,index,0); WORD wFileCount = (WORD)SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_SELECTOR,PSM_GETFILECOUNT,index,0); wTotalFiles += wFileCount; if (pPackageInfo->fSelected) { wSelectCount++; if (pPackageInfo->fOptional) // optional, selected? { fMainOnly = false; } // calc package size wSelectFiles += wFileCount; } for (WORD index2 = 0;index2 < wFileCount;index2++) { PS_FILEINFO *pFileInfo = (PS_FILEINFO*)SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_SELECTOR,PSM_GETFILEINFO,index2,(LPARAM)pPackageInfo); if (pPackageInfo->fSelected) { dwSelectSize += pFileInfo->dwFileSize; } dwTotalSize += pFileInfo->dwFileSize; } } bool fSelectAll = false, fSelectMain = false; // are we selecting all? if (wSelectCount != 0) // we got smt { if (wSelectCount == wCount) // total (won't compile on non-VC, damn MS and their non-ANSI crap) { fSelectAll = true; } else if (fMainOnly) { fSelectMain = true; } if (!IsWindowEnabled(GetDlgItem(hwndDlg,IDC_PACKAGEDLG_INSTALLMAIN))) { fSelectMain = false; } } else // uncheck both buttons { fSelectAll = false; fSelectMain = false; } // we don't use CheckRadioButton() coz both buttons might be unselected SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_INSTALLALL,BM_SETCHECK,((fSelectAll) ? (BST_CHECKED) : (BST_UNCHECKED)),0); SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_INSTALLMAIN,BM_SETCHECK,((fSelectMain) ? (BST_CHECKED) : (BST_UNCHECKED)),0); // if one of these, then we can save it EnableWindow(GetDlgItem(hwndDlg,IDC_PACKAGEDLG_DOTHESAME),fSelectAll || fSelectMain); // enable or disable accordingly EnableWindow(GetDlgItem(hwndDlg,IDOK),wSelectCount != 0); // ok now show some info about our selection char szTemp[32], szTemp2[32], szTemp3[128]; // not the best choice for variables naming, hehe :) // package num wsprintf(szTemp,"%d/%d",wSelectCount,SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_SELECTOR,PSM_GETPACKAGECOUNT,0,0)); SetDlgItemText(hwndDlg,IDC_PACKAGEDLG_STATIC_SELPACKAGES,szTemp); // size Format_DisplaySize(szTemp,dwSelectSize); Format_DisplaySize(szTemp2,dwTotalSize); wsprintf(szTemp3,"%s/%s",szTemp,szTemp2); SetDlgItemText(hwndDlg,IDC_PACKAGEDLG_STATIC_SELSIZE,szTemp3); // file count wsprintf(szTemp,"%d/%d",wSelectFiles,wTotalFiles); SetDlgItemText(hwndDlg,IDC_PACKAGEDLG_STATIC_SELFILES,szTemp); return(true); } break; case WM_CLOSE: { // return type EndDialog(hwndDlg,0xFF); return(true); } break; } return(false); } // returns true on good // returns false on bad // :) // bInstallSolution is given by reference // needs to be changeable // but pointers are getting annoying :) // returns: // 0 - good // 1 - error // 2 - cancel __forceinline byte Extract_File(HWND hwndDlg,int iItemID,byte &bInstallSolution,const char *szSrcFile,const char *szDestDir) { unzFile hFile = unzOpen(szSrcFile); if (hFile != NULL) { // hmm this used to work different // now it works this way: script is loaded here, and unloaded when done // in a nutshell: it's only loaded once for the installation process, which is good :) if (unzLocateFile(hFile,INSTALLSCRIPT_FILENAME,2) == UNZ_OK) // try to find the installation script (insensitive) { // we got a script! // with l_bInstallSolution 0 - ask user with dialog, 1 - all, 2 - main unz_file_info fileInfo; unzGetCurrentFileInfo(hFile,&fileInfo,NULL,0,NULL,0,NULL,0); // we need its size if (fileInfo.uncompressed_size > 0) // valid { if (unzOpenCurrentFile(hFile) == UNZ_OK) { // how installation takes place: // 1. through the packages dialog - the dialog lets the user chooose // what packages he/she wants to install. The dialog returns a // WORKER_FILELIST* list // 2. through parser handler - the parser receives the installation // solution hint, and forms a WORKER_FILELIST* list accordingly char szPackages[32]; WORD wPackagesCount; // if we only have one package to install ListView_GetItemText(GetDlgItem(hwndDlg,IDC_INSTALLATIONS),iItemID,4,szPackages,32); wPackagesCount = atoi(strchr(szPackages,'/')+1); // find info on all packages and get it in the selection control char *lpScriptBuffer = new char[fileInfo.uncompressed_size + 1]; // the script can't be that big // that's the basic assumption here int iResult = unzReadCurrentFile(hFile,lpScriptBuffer,fileInfo.uncompressed_size); if (iResult < 0) // error { // no script, some error delete [] lpScriptBuffer; unzCloseCurrentFile(hFile); unzClose(hFile); return(1); } if (unzCloseCurrentFile(hFile) == UNZ_CRCERROR) { // no script, CRC error delete [] lpScriptBuffer; unzClose(hFile); return(1); } lpScriptBuffer[fileInfo.uncompressed_size] = '\0'; // close it if ((!bInstallSolution) && (wPackagesCount > 1)) { // installation solution is returned (used for more packages later, if needed) // all the dialog has to do, is read the current open file (the script is already positioned, it only has to be read) PACKAGEDLG_EXTRAINFO *pExtraInfo = new PACKAGEDLG_EXTRAINFO; // deleted by us after dialog dies pExtraInfo->hFile = hFile; pExtraInfo->szFilename = strrchr(szSrcFile,'\\') + 1; pExtraInfo->pFileList = NULL; pExtraInfo->lpScript = lpScriptBuffer; byte bResult = DialogBoxParam(g_hInstance,MAKEINTRESOURCE(IDD_PACKAGESDIALOG),hwndDlg,PackagesDlgProc,(LPARAM)pExtraInfo); if (bResult == 0xFF) { // we don't install, let's leave (user hit Cancel) // clean up Cleanup_FileList(&(pExtraInfo->pFileList)); delete pExtraInfo; delete [] lpScriptBuffer; unzClose(hFile); return(2); } else { bInstallSolution = bResult; } // okay, now we have our installation list // we *always* have installation files // no way did we come all this way and we can't install this :) bool fError = false; GENERAL_FILELIST *pFileList = pExtraInfo->pFileList; while (pFileList != NULL) { // backslashes to slashes Switch_Slashes(pFileList->lpFilename,true); // no need to switch slashes here, control items were already switched if (unzLocateFile(hFile,pFileList->lpFilename,2) != UNZ_OK) // try to find the file { fError = true; break; // argg } if (!Worker_InstallFile(hFile,hwndDlg,iItemID,szDestDir)) // error has occured { fError = true; break; // stop installing (we don't give a warning here, the user already got it) } pFileList = pFileList->next; } // clean up Cleanup_FileList(&(pExtraInfo->pFileList)); delete pExtraInfo; if (fError) { delete [] lpScriptBuffer; unzClose(hFile); return(1); } } else // install all (or just one package), or main { // call XML handler XMLINSTALLER_EXTRAINFO *pExtraInfo = new XMLINSTALLER_EXTRAINFO; pExtraInfo->bSolution = (((bInstallSolution == 1) || (wPackagesCount == 1)) ? (1) : (2)); // or one package/all, or main pExtraInfo->pFileList = NULL; // ok now process script XMLParser_FeedDocument(XMLHandler_GetFilesPackages,lpScriptBuffer,(DWORD)pExtraInfo); // start installing GENERAL_FILELIST *pFileList = pExtraInfo->pFileList; bool fError = false; while (pFileList != NULL) { // backslashes to slashes Switch_Slashes(pFileList->lpFilename,true); if (unzLocateFile(hFile,pFileList->lpFilename,2) != UNZ_OK) // try to find the file { fError = true; break; // argg } if (!Worker_InstallFile(hFile,hwndDlg,iItemID,szDestDir)) { fError = true; break; } pFileList = pFileList->next; } // ok now we have everything Cleanup_FileList(&(pExtraInfo->pFileList)); delete pExtraInfo; if (fError) { delete [] lpScriptBuffer; unzClose(hFile); return(1); } } // autorun goes here // here we try to use autorun section AUTORUN_INFO *pARInfo = new AUTORUN_INFO; pARInfo->lpFilename = NULL; pARInfo->bState = 0; XMLParser_FeedDocument(XMLHandler_InspectAutorun,lpScriptBuffer,(DWORD)pARInfo); // handle it if ((pARInfo->bState & 1) && (pARInfo->lpFilename != NULL)) // got it { if (unzLocateFile(hFile,pARInfo->lpFilename,2) == UNZ_OK) // found file { // check that filetype matches given type char *lpExtension = strrchr(pARInfo->lpFilename,'.') + 1; // extension if (lpExtension == NULL) // no extension { pARInfo->bState &= ~2; // not a document, AFAIK } if ((pARInfo->bState & 2) && (!((lstrcmpi(lpExtension,"txt") == 0) || (lstrcmpi(lpExtension,"htm") == 0) || (lstrcmpi(lpExtension,"html") == 0)))) { // NOT a document pARInfo->bState &= ~2; } bool fContinue = true; if ((!(pARInfo->bState & 2)) || (g_WorkOptions.dwFlags & 1)) // not a document, or, we always have to ask { char szMsg[512]; Switch_Slashes(pARInfo->lpFilename,false); // switch it, to make it displayable wsprintf(szMsg,Translate("The installation wants to autorun a file, named \"%s\". Would you like to run it?"),pARInfo->lpFilename); if (MessageBox(hwndDlg,szMsg,Translate("Miranda Installer"),MB_YESNO | MB_ICONINFORMATION | MB_DEFBUTTON2) == IDNO) // default button is No, to avoid any fast clicks, being careful is good :) { fContinue = false; } else // switch back (needed later) { Switch_Slashes(pARInfo->lpFilename,true); } } if (fContinue) // move on { // here we extract the file to a temp dir (with the same file extension) // and run it if (unzOpenCurrentFile(hFile) == UNZ_OK) { // build filename char szDest[MAX_PATH+1]; GetTempPath(MAX_PATH+1,szDest); char *lpFilename = strrchr(pARInfo->lpFilename,'/'); if (lpFilename == NULL) { lpFilename = pARInfo->lpFilename; } else { lpFilename++; } lstrcat(szDest,lpFilename); // only add the filename FILE *hARFile = fopen(szDest,"wb"); if (hARFile != NULL) { char szData[2048]; while (1) { int iRead = unzReadCurrentFile(hFile,szData,sizeof(szData)); if (iRead > 0) { if (fwrite(szData,1,iRead,hARFile) != (unsigned int)iRead) { break; } } else { break; } } fclose(hARFile); } unzCloseCurrentFile(hFile); // close the file (don't care about errors, we're done with this file) ShellExecute(NULL,"open",szDest,NULL,NULL,SW_SHOW); } } // fContinue } // found file in zip } if (pARInfo->lpFilename != NULL) { delete [] pARInfo->lpFilename; } delete pARInfo; // done with script delete [] lpScriptBuffer; } } } else // we don't have a script { // perform a dirty, dirty installaion (file-by-file) if (unzGoToFirstFile(hFile) == UNZ_OK) { do { if (!Worker_InstallFile(hFile,hwndDlg,iItemID,szDestDir)) { unzClose(hFile); return(1); } } while (unzGoToNextFile(hFile) == UNZ_OK); } } unzClose(hFile); return(0); } return(1); } DWORD WINAPI InstallerProc(LPVOID lpParameter) { // about installing language packs - this is Kai's (kai_b) solution, works out great btw :) // language packs are installed in the "usual" language directory // if the whole "batch" of installations included a language pack installation, then // the user will be asked which one should be used (that is, only if more than one language pack is available) // the "active" language pack is also copied to the language directory (there's no need to remember it, because it'll be copied last/first, so we can "know" it's the active one) // this whole process isn't done here, it's done by the caller thread later // do checks for g_fStopThread HWND hwndDlg = (HWND)lpParameter; HWND hListView = GetDlgItem(hwndDlg,IDC_INSTALLATIONS); LVITEM lvItem; char *lpDestDir = NULL; char szPluginsDir[MAX_PATH + 1]; // *might* be needed lstrcpy(szPluginsDir,g_WorkOptions.szMirandaDirectory); lstrcat(szPluginsDir,"\\Plugins"); SendMessage(hwndDlg,MIRINST_INFOMSG_STARTING,0,0); byte bInstallSolution = (byte)((g_WorkOptions.dwFlags & 6) >> 1); // init to setting from options bool fMasterError = false; // true if some error occured while installing for (int index=0, iCount=ListView_GetItemCount(hListView);index < iCount;index++) { if (g_fStopThread) { PostMessage(hwndDlg,MIRINST_INFOMSG_DONE,0,0); ExitThread(1); } lvItem.mask = LVIF_PARAM; lvItem.iSubItem = 0; lvItem.iItem = index; ListView_GetItem(hListView,&lvItem); ADDON_LISTINFO *pListInfo = (ADDON_LISTINFO*)lvItem.lParam; // work out the dest dir according to type switch(pListInfo->bType) { case INSTALLTYPE_PLUGIN: lpDestDir = szPluginsDir; break; case INSTALLTYPE_ICON: lpDestDir = g_WorkOptions.szIconDirectory; break; case INSTALLTYPE_SOUND: lpDestDir = g_WorkOptions.szSoundDirectory; break; case INSTALLTYPE_LANGUAGE: lpDestDir = g_WorkOptions.szLangDirectory; break; case INSTALLTYPE_TOOL: lpDestDir = g_WorkOptions.szToolDirectory; break; case INSTALLTYPE_SOURCE: lpDestDir = g_WorkOptions.szSrcDirectory; break; case INSTALLTYPE_DOC: lpDestDir = g_WorkOptions.szDocDirectory; break; case INSTALLTYPE_SKIN: lpDestDir = g_WorkOptions.szSkinDirectory; break; case INSTALLTYPE_NIGHTLY: lpDestDir = g_WorkOptions.szMirandaDirectory; break; } // great SendMessage(hwndDlg,MIRINST_INFOMSG_STARTITEM,index,0); byte bResult = Extract_File(hwndDlg,index,bInstallSolution,pListInfo->lpFilePath,lpDestDir); // install solution is changeable SendMessage(hwndDlg,MIRINST_INFOMSG_FINISHEDITEM,index,bResult); // we report an error if (bResult == 1) { fMasterError = true; } // any changes to listview items is done by the master window. bahh! :) } PostMessage(hwndDlg,MIRINST_INFOMSG_DONE,fMasterError,0); ExitThread(0); }